package de.unibi.comet.tools;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import de.unibi.comet.fa.Alphabet;
import de.unibi.comet.fa.CDFA;
import de.unibi.comet.fa.DFAFactory;
import de.unibi.comet.fa.DnaMotifParser;
import de.unibi.comet.fa.GeneralizedString;
import de.unibi.comet.util.Log;

public class dna_assess_motif {

	public static void usage() {
		System.out.println("usage: dna_assess_motif <genome> <patternfile>");
		System.out.println("   <genome> file containing the plain (not fasta) genome");
		System.out.println("   <patternfile> file containing the patterns to investigate");
		System.exit(1);
	}

	public static int naiveMatch(String s, List<GeneralizedString> pl) {
		Log.getInstance().startTimer();
		int matches=0;
		for (int i=0; i<s.length(); ++i) {
			for (GeneralizedString pattern : pl) {
				if (pattern.matches(s, i)) {
					matches+=1;
					// Log.getInstance().printNormal(String.format("m %d (%s)", i+pattern.length()-1, s.substring(i, i+pattern.length())));
					// Log.getInstance().printNormal(String.format("m %d", i+pattern.length()-1));
					// break;
				}
			}
		}
		Log.getInstance().stopTimer("naive matching");
		return matches;
	}
	
	public static double[] getEmpiricDistribution(Alphabet alphabet, String s) {
		Log.getInstance().startTimer();
		double[] freq = new double[alphabet.size()];
		for (int i=0; i<s.length(); ++i) {
			freq[alphabet.getIndex(s.charAt(i))]+=1;
		}
		for (int i=0; i<freq.length; ++i) {
			freq[i]/=(double)s.length();
		}
		Log.getInstance().stopTimer("Determine empiric distribution");
		return freq;
	}
	
	public static void main(String[] args) {
		if (args.length!=2) usage();
		
		String genome = null;
		FileInputStream genomeFile = null;
		try {
			genomeFile = new FileInputStream(args[0]);
		} catch (FileNotFoundException e) {
			System.out.println("File not found, sorry!");
			System.exit(1);
		}
		BufferedReader br = new BufferedReader(new InputStreamReader(genomeFile));
		try {
			String line = br.readLine();
			if (line==null) {
				System.out.println("Couldn't read genome");
				System.exit(1);
			}
			genome=line;
			System.out.println(String.format("Read genome: %d characters", genome.length()));
		} catch (IOException e) {
			System.out.println("I/O failure, sorry!");
			System.exit(1);
		}
		
		FileInputStream patternFile = null;
		try {
			patternFile = new FileInputStream(args[1]);
		} catch (FileNotFoundException e) {
			System.out.println("File not found, sorry!");
			System.exit(1);
		}
		br = new BufferedReader(new InputStreamReader(patternFile));
		ArrayList<String> l = new ArrayList<String>();
		try {
			while (true) {
				String line = br.readLine();
				if (line==null) break;
				l.add(line);
//				System.out.printf("line: %s\n",line);
			}
		} catch (IOException e) {
			System.out.println("I/O failure, sorry!");
			System.exit(1);
		}

		Log.getInstance().setTimingActive(true);
		// Log.getInstance().setLogLevel(Log.Level.INSANE);
		Log.getInstance().setLogLevel(Log.Level.EVERYTHING);

		Alphabet alphabet = DnaMotifParser.getDnaAlphabet();
		double[] charDist = getEmpiricDistribution(alphabet, genome);
		
		for (String s : l) {
			Log.getInstance().startTimer();
			ArrayList<GeneralizedString> genStringList = new ArrayList<GeneralizedString>();
			StringTokenizer st = new StringTokenizer(s,",",false);
			while (st.hasMoreTokens()) genStringList.add(DnaMotifParser.parse(st.nextToken()));
			CDFA cdfa = DFAFactory.build(alphabet, genStringList);
			double timeConstruction = Log.getInstance().getLastPeriodCpu();
			int nodes = cdfa.getStateCount();
			cdfa = cdfa.minimizeHopcroft();
			double timeMinimization = Log.getInstance().getLastPeriodCpu();
			int nodesMinimized = cdfa.getStateCount();

			// calculate expectation
			Log.getInstance().startTimer();
			double expectation = 0.0;
			for (GeneralizedString p : genStringList) {
				double e = genome.length() - p.length() +1;
				expectation+=e*p.getProbability(charDist);
			}
			Log.getInstance().stopTimer("Calculate expectation");
			
			int matches = cdfa.countMatchesDFA(genome);
			// verification if automaton was constructed correctly
//			int naiveMatches = naiveMatch(genome, genStringList);
//			if (matches!=naiveMatches) {
//				System.out.println(String.format(">! MISMATCH!: %d, naive matches: %d (\"%s\")", matches, naiveMatches, s));
//				Log.getInstance().stopTimer("Whole experiment");
//				continue;
//			}
				
			System.out.println(String.format("> %s %d %e %e %d %d %e %e", s, matches, expectation, ((double)matches)/expectation, nodes, nodesMinimized, timeConstruction, timeMinimization));
			Log.getInstance().stopTimer("Whole experiment");
		}
	}
}
